import sys
import os
import time
from PyQt5.QtWidgets import (
    QWidget,
    QApplication,
    QAbstractItemView,
    QFileDialog,
    QMessageBox,
    QInputDialog
)
from PyQt5.QtCore import QStringListModel, pyqtSlot, QModelIndex
from ui.Ui_main_window import Ui_Form
from util.file_encryption import encrypt_model
from util.update_encryption import (
    update_IV,
    update_x1_model,
    scan_all_ivs,
    update_ivs,
    update_model_files,
)
from util.rebuild_nativlibs import run_gradle_rebuild, copy_so_2_x1, copy_model_2_x1
from util.BuildThread import BuildThread
from Config import AppConfig
from widget.windowUtil import WindowUtil

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.setWindowTitle("模型更新工具")
        # 初始化线程变量
        self.build_thread = None
        self.window_util = WindowUtil(self)

    @pyqtSlot()
    def on_select_x1_path_clicked(self):
        """选择X1项目路径并验证有效性"""
        folder_path = QFileDialog.getExistingDirectory(
            self,
            "选择X1项目路径",
            "",
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks,
        )
        if not folder_path:
            self.ui.log.append("未选择路径")
            return

        # 验证路径有效性
        required_paths = [
            os.path.join(folder_path, "x1ScannerApp"),
            os.path.join(folder_path, "nativelibs"),
        ]
        for path in required_paths:
            if not os.path.exists(path):
                QMessageBox.warning(self, "路径无效", f"缺少必要目录：{path}")
                return

        # 保存配置
        AppConfig.root_project_path = folder_path
        AppConfig.x1_project_path = os.path.join(folder_path, "x1ScannerApp")
        AppConfig.nativelibs_project_path = os.path.join(folder_path, "nativelibs")
        AppConfig.cryption_cpp_file = os.path.join(
            folder_path,
            "nativeLibs/app/src/main/cpp/cryption/model_file_decryption_iv.cpp",
        )
        AppConfig.quantized_kotlin_path = os.path.join(
            AppConfig.x1_project_path,
            r"decoder/src/main/java/com/action/ai/x1/decoder/model/ModelQuantParam.kt",
        )

        self.ui.log.append(f"已选择X1项目路径: {folder_path}")

    @pyqtSlot()
    def on_select_model_path_clicked(self):
        """选择模型文件并验证格式"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择需要更新的模型文件", "", "Model Files (*.dlc);;All Files (*)"
        )
        if not file_path:
            self.ui.log.append("未选择模型文件")
            return

        # 验证文件格式
        if not file_path.endswith(".dlc"):
            QMessageBox.warning(self, "格式错误", "请选择.dlc格式的模型文件")
            return

        # 保存配置
        model_filename = os.path.basename(file_path)
        AppConfig.model_path = file_path
        # 确保加密模型目录存在
        if not os.path.exists(AppConfig.encrypted_model_path):
            os.makedirs(AppConfig.encrypted_model_path)
        AppConfig.model_name = model_filename.split(".")[0]
        AppConfig.encrypted_model_path = os.path.join(
            AppConfig.encrypted_model_path, f"{AppConfig.model_name}.dll"
        )
        AppConfig.quantized_html_path = AppConfig.model_path.replace(".dlc", ".html")
        self.ui.log.append(f"已选择模型文件: {file_path}")
    
    @pyqtSlot()
    def on_update_clicked(self):
        """处理模型更新（拆分逻辑为子方法）"""
        if not self.window_util._check_preconditions():
            return
        try:
            self.ui.log.append("开始加密模型...")
            self.iv = encrypt_model(
                AppConfig.model_path, AppConfig.encrypted_model_path
            )
            self.ui.log.append(f"模型加密完成，IV: {self.iv}")

            self.ui.log.append("扫描现有IV列表...")
            self.simple_ivs, self.map_ivs = scan_all_ivs(AppConfig.cryption_cpp_file)
            self.window_util.simple_ivs = self.simple_ivs
            self.window_util.map_ivs = self.map_ivs
            self.window_util.on_show_ivs_popup()
            # self.display_ivs_in_listview(self.simple_ivs, self.map_ivs)
            self.ui.log.append("IV列表加载完成，请选择需要更新的项")
        except Exception as e:
            self.ui.log.append(f"更新失败: {str(e)}")
            QMessageBox.critical(self, "操作失败", f"发生错误: {str(e)}")
    @pyqtSlot()
    def on_add_clicked(self):
        """处理新增模型（拆分逻辑为子方法）"""
        if not self.window_util._check_preconditions():
            return
        print("add clicked")
        # ===========================
        # 1.加密模型
        # 2.更新cpp文件with新的IV
        # ===========================
        try:
            self.ui.log.append("开始加密模型...")
            self.iv = encrypt_model(
                AppConfig.model_path, AppConfig.encrypted_model_path
            )
            self.ui.log.append(f"模型加密完成，IV: {self.iv}")
            # 弹出输入框，输入模型名称
            dialog = QInputDialog(self)
            dialog.setInputMode(QInputDialog.TextInput)
            dialog.setLabelText("请输入模型名称:")
            dialog.setWindowTitle("输入模型名称")
            dialog.resize(400, 400)  # 设置宽度为400，高度为100
            dialog.setTextValue("")   # 可设置默认值

            if dialog.exec_() == QInputDialog.Accepted:
                model_name = dialog.textValue()
                print(f"输入的模型名称: {model_name}")
            elif dialog.exec_() == QInputDialog.Rejected:
                self.ui.log.append("取消输入")
                QMessageBox.critical(self, "操作失败", "取消输入")
                return
            addCPPFile(AppConfig.cryption_cpp_file, model_name, self.iv)
            AppConfig.cryption_cpp_file
        except Exception as e:
            self.ui.log.append(f"添加新模型失败: {str(e)}")
            QMessageBox.critical(self, "操作失败", f"发生错误: {str(e)}")
        pass


    @pyqtSlot()
    def on_updateCpp_clicked(self):
        """处理确认按钮点击事件"""
        if self.window_util.selected_index < len(self.simple_ivs):
            sel_simple = [self.window_util.selected_index]
            sel_map = []
        else:
            sel_simple = []
            sel_map = [self.window_util.selected_index - len(self.simple_ivs)]
        item_text = self.window_util.selected_text
        self.model_text = item_text
        self.ui.log.append(f"开始处理: {item_text}")
        update_ivs(
            AppConfig.cryption_cpp_file,
            AppConfig.cryption_cpp_file,
            self.iv,
            self.simple_ivs,
            self.map_ivs,
            sel_simple,
            sel_map,
        )
        self.ui.update.setEnabled(False)
        self.ui.updateCpp.setEnabled(False)
        # 更新X1模型
        self.ui.log.append("开始更新X1模型...")
        model_file_path = os.path.join(
            AppConfig.x1_project_path,
            "decoder/src/main/java/com/action/ai/x1/decoder/model/ModelFile.kt",
        )
        print(f"🔍 扫描 ModelFile.kt 文件...{model_file_path}")

        if not os.path.exists(model_file_path):
            print(f"❌ ModelFile.kt 文件不存在: {model_file_path}")
            return
        from util.update_encryption import scan_all_model_files

        self.simple_ivs, self.map_ivs = scan_all_model_files(model_file_path)
        self.window_util.simple_ivs = self.simple_ivs
        self.window_util.map_ivs = self.map_ivs
        self.window_util.on_show_ivs_popup()
        self.ui.updateX1ModelFile.setEnabled(True)
    # @pyqtSlot()
    # def on_compile_clicked(self):
    #     """处理编译按钮点击事件"""
    #     # 创建并启动工作线程
    #     self.build_thread = BuildThread(
    #         AppConfig.nativelibs_project_path,
    #     )
    #     # 连接信号
    #     self.build_thread.log_signal.connect(self.on_thread_log)
    #     self.build_thread.finished_signal.connect(self.on_build_finished)
    #     # 启动线程
    #     self.build_thread.start()

    @pyqtSlot()
    def on_updateX1ModelFile_clicked(self):
        """处理确认按钮点击事件"""

        # 获取选中项的索引
        if self.window_util.selected_index < len(self.simple_ivs):
            sel_simple = [self.window_util.selected_index]
            sel_map = []
        else:
            sel_simple = []
            sel_map = [self.window_util.selected_index - len(self.simple_ivs)]
        item_text = self.window_util.selected_text
        self.ui.log.append(f"开始处理: {item_text}")
        model_file_path = os.path.join(
            AppConfig.x1_project_path,
            "decoder/src/main/java/com/action/ai/x1/decoder/model/ModelFile.kt",
        )
        new_model_path = f"encrypted_model_files/qr/{AppConfig.model_name}.dll"
        update_model_files(
            model_file_path,
            model_file_path,
            new_model_path,
            self.simple_ivs,
            self.map_ivs,
            sel_simple,
            sel_map,
        )
        self.ui.log.append("X1模型更新完成")
        self.ui.updateX1ModelFile.setEnabled(False)

        # # 复制模型文件
        # self.ui.log.append(f"开始复制模型文件...{AppConfig.encrypted_model_path}")
        # copy_model_2_x1(AppConfig.encrypted_model_path, AppConfig.x1_project_path)
        # self.ui.log.append("模型文件复制完成")

    # @pyqtSlot(str)
    # def on_thread_log(self, message):
    #     """处理线程发送的日志信息"""
    #     self.ui.log.append(message)

    # @pyqtSlot(bool)
    # def on_build_finished(self, success):
    #     """处理构建完成信号"""
    #     if success:
    #         self.ui.log.append("开始执行后续操作...")
    #         try:
    #             time.sleep(1)
    #             # 复制SO文件
    #             self.ui.log.append("开始复制SO文件...")
    #             copy_so_2_x1(
    #                 AppConfig.nativelibs_project_path, AppConfig.x1_project_path
    #             )
    #             self.ui.log.append("SO文件复制完成")
    #         except Exception as e:
    #             self.ui.log.append(f"后续操作执行失败: {str(e)}")
    #     else:
    #         self.ui.log.append("构建失败，跳过后续操作")

    #     # 清理线程
    #     if self.build_thread:
    #         self.build_thread.deleteLater()
    #         self.build_thread = None

    @pyqtSlot()
    def on_confirm_quant_clicked(self):
        """处理确认按钮点击事件"""
        from util.extract_quant import extract_encoding_values

        quant_params = extract_encoding_values(AppConfig.quantized_html_path)
        self.ui.log.append(f"开始处理量化参数: {quant_params}")
        self.ui.log.append(f"model_text: {self.model_text}")
        model_name = self.model_text.split(" ")[1].split("::")[1]
        Model_type = f"AreaType.{model_name}"
        
        offset1 = quant_params["input_encoding"]["offset"]
        offset1 = float(offset1)
        offset1 = int(offset1) if offset1.is_integer() else offset1
        offset1=abs(offset1)
        from util.update_quant_param import modify_pair_values
        modify_pair_values(
            AppConfig.quantized_kotlin_path,
            Model_type,
            1,
            quant_params["input_encoding"]["scale"]+"f",
            offset1
        )
        offset1 = quant_params["output_encoding"]["offset"]
        offset1 = float(offset1)
        offset1 = int(offset1) if offset1.is_integer() else offset1
        offset1=abs(offset1)
        from util.update_quant_param import modify_pair_values
        modify_pair_values(
            AppConfig.quantized_kotlin_path,
            Model_type,
            2,
            quant_params["output_encoding"]["scale"]+"f",
            offset1
        )
        self.ui.update.setEnabled(True)
        self.ui.updateCpp.setEnabled(True)
        self.ui.updateX1ModelFile.setEnabled(True)
    @pyqtSlot()
    def on_clear_clicked(self):
        """处理清空按钮点击事件"""
        self.ui.log.clear()
        AppConfig.model_name = ""
        AppConfig.model_path = ""
        AppConfig.quantized_html_path = ""
        AppConfig.encrypted_model_path = "./backup/model/"
        self.ui.update.setEnabled(True)
        self.ui.updateCpp.setEnabled(True)
        self.ui.updateX1ModelFile.setEnabled(True)


def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
